home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / Delphi 3.0 / DATA.Z / comserv.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1997-01-29  |  9.0 KB  |  366 lines

  1.  
  2. {*******************************************************}
  3. {                                                       }
  4. {       Delphi Runtime Library                          }
  5. {                                                       }
  6. {       Copyright (C) 1997 Borland International        }
  7. {                                                       }
  8. {*******************************************************}
  9.  
  10. unit ComServ;
  11.  
  12. {$DENYPACKAGEUNIT}
  13.  
  14. interface
  15.  
  16. uses Windows, ActiveX, SysUtils, ComObj;
  17.  
  18. type
  19.  
  20. { Application start mode }
  21.  
  22.   TStartMode = (smStandalone, smAutomation, smRegServer, smUnregServer);
  23.  
  24. { Class manager event types }
  25.  
  26.   TLastReleaseEvent = procedure(var Shutdown: Boolean) of object;
  27.  
  28. { TComServer }
  29.  
  30.   TComServer = class(TComServerObject)
  31.   private
  32.     FObjectCount: Integer;
  33.     FFactoryCount: Integer;
  34.     FTypeLib: ITypeLib;
  35.     FServerName: string;
  36.     FHelpFileName: string;
  37.     FIsInprocServer: Boolean;
  38.     FStartMode: TStartMode;
  39.     FRegister: Boolean;
  40.     FOnLastRelease: TLastReleaseEvent;
  41.     procedure FactoryFree(Factory: TComObjectFactory);
  42.     procedure FactoryRegisterClassObject(Factory: TComObjectFactory);
  43.     procedure FactoryUpdateRegistry(Factory: TComObjectFactory);
  44.     procedure LastReleased;
  45.   protected
  46.     function CountObject(Created: Boolean): Integer; override;
  47.     function CountFactory(Created: Boolean): Integer; override;
  48.     function GetHelpFileName: string; override;
  49.     function GetServerFileName: string; override;
  50.     function GetServerKey: string; override;
  51.     function GetServerName: string; override;
  52.     function GetTypeLib: ITypeLib; override;
  53.   public
  54.     constructor Create;
  55.     destructor Destroy; override;
  56.     procedure Initialize;
  57.     procedure LoadTypeLib;
  58.     procedure SetServerName(const Name: string);
  59.     procedure UpdateRegistry(Register: Boolean);
  60.     property IsInprocServer: Boolean read FIsInprocServer write FIsInprocServer;
  61.     property ObjectCount: Integer read FObjectCount;
  62.     property StartMode: TStartMode read FStartMode;
  63.     property OnLastRelease: TLastReleaseEvent read FOnLastRelease write FOnLastRelease;
  64.   end;
  65.  
  66. var
  67.   ComServer: TComServer;
  68.  
  69. function DllGetClassObject(const CLSID, IID: TGUID; var Obj): HResult; stdcall;
  70. function DllCanUnloadNow: HResult; stdcall;
  71. function DllRegisterServer: HResult; stdcall;
  72. function DllUnregisterServer: HResult; stdcall;
  73.  
  74. implementation
  75.  
  76. {$I ComServ.inc}
  77.  
  78. { Find command-line switch }
  79.  
  80. function FindCmdLineSwitch(const Switch: string): Boolean;
  81. var
  82.   I: Integer;
  83.   S: string;
  84. begin
  85.   for I := 1 to ParamCount do
  86.   begin
  87.     S := ParamStr(I);
  88.     if (S[1] in ['-', '/']) and
  89.       (CompareText(Copy(S, 2, Maxint), Switch) = 0) then
  90.     begin
  91.       Result := True;
  92.       Exit;
  93.     end;
  94.   end;
  95.   Result := False;
  96. end;
  97.  
  98. function GetModuleFileName: string;
  99. var
  100.   Buffer: array[0..261] of Char;
  101. begin
  102.   SetString(Result, Buffer, Windows.GetModuleFileName(HInstance,
  103.     Buffer, SizeOf(Buffer)));
  104. end;
  105.  
  106. function GetModuleName: string;
  107. begin
  108.   Result := ChangeFileExt(ExtractFileName(GetModuleFileName), '');
  109. end;
  110.  
  111. function LoadTypeLibrary(const ModuleName: string): ITypeLib;
  112. begin
  113.   OleCheck(LoadTypeLib(PWideChar(WideString(ModuleName)), Result));
  114. end;
  115.  
  116. procedure RegisterTypeLibrary(TypeLib: ITypeLib; const ModuleName: string);
  117. var
  118.   Name: WideString;
  119. begin
  120.   Name := ModuleName;
  121.   OleCheck(RegisterTypeLib(TypeLib, PWideChar(Name), PWideChar(Name)));
  122. end;
  123.  
  124. procedure UnregisterTypeLibrary(TypeLib: ITypeLib);
  125. type
  126.   TUnregisterProc = function(const GUID: TGUID; VerMajor, VerMinor: Word;
  127.     LCID: TLCID; SysKind: TSysKind): HResult stdcall;
  128. var
  129.   Handle: THandle;
  130.   UnregisterProc: TUnregisterProc;
  131.   LibAttr: PTLibAttr;
  132. begin
  133.   Handle := GetModuleHandle('OLEAUT32.DLL');
  134.   if Handle <> 0 then
  135.   begin
  136.     @UnregisterProc := GetProcAddress(Handle, 'UnRegisterTypeLib');
  137.     if @UnregisterProc <> nil then
  138.     begin
  139.       OleCheck(ComServer.TypeLib.GetLibAttr(LibAttr));
  140.       with LibAttr^ do
  141.         UnregisterProc(guid, wMajorVerNum, wMinorVerNum, lcid, syskind);
  142.       ComServer.TypeLib.ReleaseTLibAttr(LibAttr);
  143.     end;
  144.   end;
  145. end;
  146.  
  147. function GetTypeLibName(TypeLib: ITypeLib): string;
  148. var
  149.   Name: WideString;
  150. begin
  151.   OleCheck(TypeLib.GetDocumentation(-1, @Name, nil, nil, nil));
  152.   Result := Name;
  153. end;
  154.  
  155. function DllGetClassObject(const CLSID, IID: TGUID; var Obj): HResult;
  156. var
  157.   Factory: TComObjectFactory;
  158. begin
  159.   Factory := ComClassManager.GetFactoryFromClassID(CLSID);
  160.   if Factory <> nil then
  161.     if Factory.GetInterface(IID, Obj) then
  162.       Result := S_OK
  163.     else
  164.       Result := E_NOINTERFACE
  165.   else
  166.   begin
  167.     Pointer(Obj) := nil;
  168.     Result := CLASS_E_CLASSNOTAVAILABLE;
  169.   end;
  170. end;
  171.  
  172. function DllCanUnloadNow: HResult;
  173. begin
  174.   with ComServer do
  175.     if (FObjectCount = 0) and (FFactoryCount = 0) then
  176.       Result := S_OK else
  177.       Result := S_FALSE;
  178. end;
  179.  
  180. function DllRegisterServer: HResult;
  181. begin
  182.   Result := S_OK;
  183.   try
  184.     ComServer.UpdateRegistry(True);
  185.   except
  186.     Result := E_FAIL;
  187.   end;
  188. end;
  189.  
  190. function DllUnregisterServer: HResult;
  191. begin
  192.   Result := S_OK;
  193.   try
  194.     ComServer.UpdateRegistry(False);
  195.   except
  196.     Result := E_FAIL;
  197.   end;
  198. end;
  199.  
  200. { Automation TerminateProc }
  201.  
  202. function AutomationTerminateProc: Boolean;
  203. begin
  204.   Result := True;
  205.   // Does StartMode matter?
  206.   if (ComServer.StartMode = smAutomation) and not ((ComServer = nil) or
  207.     (ComServer.ObjectCount = 0)) then
  208.   begin
  209.     Result := MessageBox(0, PChar(SNoCloseActiveServer),
  210.       PChar(SAutomationWarning), MB_YESNO or MB_TASKMODAL or
  211.       MB_ICONWARNING or MB_DEFBUTTON2) = IDYES;
  212.   end;
  213. end;
  214.  
  215. { TComServer }
  216.  
  217. constructor TComServer.Create;
  218. begin
  219.   FTypeLib := nil;
  220.   FIsInprocServer := ModuleIsLib;
  221.   if FindCmdLineSwitch('AUTOMATION') or FindCmdLineSwitch('EMBEDDING') then
  222.     FStartMode := smAutomation
  223.   else if FindCmdLineSwitch('REGSERVER') then
  224.     FStartMode := smRegServer
  225.   else if FindCmdLineSwitch('UNREGSERVER') then
  226.     FStartMode := smUnregServer;
  227. end;
  228.  
  229. destructor TComServer.Destroy;
  230. begin
  231.   ComClassManager.ForEachFactory(Self, FactoryFree);
  232. end;
  233.  
  234. function TComServer.CountObject(Created: Boolean): Integer;
  235. begin
  236.   if Created then Inc(FObjectCount) else
  237.   begin
  238.     Dec(FObjectCount);
  239.     if FObjectCount = 0 then LastReleased;
  240.   end;
  241.   Result := FObjectCount;
  242. end;
  243.  
  244. function TComServer.CountFactory(Created: Boolean): Integer;
  245. begin
  246.   if Created then Inc(FFactoryCount) else Dec(FFactoryCount);
  247.   Result := FFactoryCount;
  248. end;
  249.  
  250. procedure TComServer.FactoryFree(Factory: TComObjectFactory);
  251. begin
  252.   Factory.Free;
  253. end;
  254.  
  255. procedure TComServer.FactoryRegisterClassObject(Factory: TComObjectFactory);
  256. begin
  257.   Factory.RegisterClassObject;
  258. end;
  259.  
  260. procedure TComServer.FactoryUpdateRegistry(Factory: TComObjectFactory);
  261. begin
  262.   if Factory.Instancing <> ciInternal then
  263.     Factory.UpdateRegistry(FRegister);
  264. end;
  265.  
  266. function TComServer.GetHelpFileName: string;
  267. begin
  268.   Result := FHelpFileName;
  269. end;
  270.  
  271. function TComServer.GetServerFileName: string;
  272. begin
  273.   Result := GetModuleFileName;
  274. end;
  275.  
  276. function TComServer.GetServerKey: string;
  277. begin
  278.   if FIsInprocServer then
  279.     Result := 'InprocServer32' else
  280.     Result := 'LocalServer32';
  281. end;
  282.  
  283. function TComServer.GetServerName: string;
  284. begin
  285.   if FServerName <> '' then
  286.     Result := FServerName
  287.   else
  288.     if FTypeLib <> nil then
  289.       Result := GetTypeLibName(FTypeLib)
  290.     else
  291.       Result := GetModuleName;
  292. end;
  293.  
  294. procedure TComServer.SetServerName(const Name: string);
  295. begin
  296.   if FTypeLib = nil then
  297.     FServerName := Name;
  298. end;
  299.  
  300. function TComServer.GetTypeLib: ITypeLib;
  301. begin
  302.   LoadTypeLib;
  303.   Result := FTypeLib;
  304. end;
  305.  
  306. procedure TComServer.Initialize;
  307. begin
  308.   UpdateRegistry(FStartMode <> smUnregServer);
  309.   if FStartMode in [smRegServer, smUnregServer] then Halt;
  310.   ComClassManager.ForEachFactory(Self, FactoryRegisterClassObject);
  311. end;
  312.  
  313. procedure TComServer.LastReleased;
  314. var
  315.   Shutdown: Boolean;
  316. begin
  317.   if not FIsInprocServer then
  318.   begin
  319.     Shutdown := FStartMode = smAutomation;
  320.     if Assigned(FOnLastRelease) then FOnLastRelease(Shutdown);
  321.     if Shutdown then PostQuitMessage(0);
  322.   end;
  323. end;
  324.  
  325. procedure TComServer.LoadTypeLib;
  326. begin
  327.   if FTypeLib = nil then FTypeLib := LoadTypeLibrary(GetModuleFileName);
  328. end;
  329.  
  330. procedure TComServer.UpdateRegistry(Register: Boolean);
  331. begin
  332.   if FTypeLib <> nil then
  333.     if Register then
  334.       RegisterTypeLibrary(FTypeLib, GetModuleFileName) else
  335.       UnregisterTypeLibrary(FTypeLib);
  336.   FRegister := Register;
  337.   ComClassManager.ForEachFactory(Self, FactoryUpdateRegistry);
  338. end;
  339.  
  340. var
  341.   SaveInitProc: Pointer = nil;
  342.  
  343. procedure InitComServer;
  344. begin
  345.   if SaveInitProc <> nil then TProcedure(SaveInitProc);
  346.   ComServer.Initialize;
  347. end;
  348.  
  349. initialization
  350. begin
  351.   ComServer := TComServer.Create;
  352.   if not IsLibrary then
  353.   begin
  354.     SaveInitProc := InitProc;
  355.     InitProc := @InitComServer;
  356.     AddTerminateProc(@AutomationTerminateProc);
  357.   end;
  358. end;
  359.  
  360. finalization
  361. begin
  362.   ComServer.Free;
  363. end;
  364.  
  365. end.
  366.